本章沿用第 26 章電商專案,加入:
完成後,系統能處理「已付款但物流失敗」這類真實情況,而不是用一個模糊的訂單狀態掩蓋問題。
台灣電商常同時依賴金流、超商物流與電子發票服務。三個外部系統各有非同步通知、測試環境與失敗狀態。若把它們串成一條必須全部成功的同步流程,只要物流暫時不可用,就可能把已完成的付款錯誤標成失敗。
本章的核心原則:訂單是商業主體,付款、物流與發票是各自可重試的外部流程。
order: pending -> confirmed -> cancelled/completed
payment: pending -> paid -> refund_pending/refunded
shipment: unselected -> ready -> created -> shipped -> delivered/failed
invoice: not_requested -> pending -> issued/failed/voided
付款成功只推進 payment;訂單可變成 confirmed,但不代表 shipment 已出貨或 invoice 已開立。每個 provider callback 都要驗證、冪等並留下事件。
完成第 26 章,準備綠界測試商店及最新金流、物流文件。商店代號、HashKey、HashIV 只放後端 secrets。正式電子發票通常涉及業者申請、稅籍與服務設定,本章不提供稅務結論,也不假裝測試碼等同正式開票資格。
請規劃現有電商的綠界金流、超商物流與電子發票邊界,不要先實作。
訂單、付款、履約、物流、發票必須使用獨立狀態與事件。
金額由既有訂單快照提供;callback 驗證 CheckMacValue、訂單、商店、金額與重複事件。
物流失敗不得回滾付款。電子發票先做 request 狀態與介面,不假設已取得正式開票資格。
請列出 Edge Functions、secrets、資料表、狀態轉換、補償流程、人工待辦和測試案例。
新增:
payments:order、provider、amount、status、provider transaction ID。payment_events:外部事件唯一鍵、驗證結果、處理摘要。shipments:order、方式、門市代碼/名稱、provider shipment ID、status。shipment_events:物流狀態、收到時間、處理結果。invoice_requests:order、發票類型、載具或統編必要欄位、status、provider invoice ID。敏感 provider payload 只保存除錯所需摘要。信用卡資訊不進入你的資料庫。
付款函式從 orders.total_twd 讀取金額,確認庫存保留仍有效,再依最新版綠界規格建立交易。瀏覽器導回頁只查詢付款狀態,不自行更新。
callback 驗證 CheckMacValue、商店、訂單、金額與 transaction ID,並在資料庫交易中:將 payment 改成 paid、order 改為 confirmed、把 reserved 轉成正式扣庫存、建立後續物流/通知工作。
請實作綠界測試付款與 payment callback。
交易金額只能讀取已建立的 order total;callback 必須驗證 CheckMacValue、MerchantID、MerchantTradeNo、TradeAmt 與 provider transaction ID。
使用事件唯一鍵避免重複入帳。成功後將 reserved inventory 轉成 sale movement,失敗時不得留下部分更新。
前端返回頁只能輪詢後端狀態,不能根據網址參數標成已付款。

圖 27-1:Sandbox 訂單先顯示 payment=processing,其餘外部流程各自保留獨立狀態。
實際重送同一個已驗證 callback 後,付款只入帳一次、庫存只扣一次,第二次事件則記為冪等忽略。

圖 27-2:inventory.deducted 只有一次,重複 callback 留下 ignored 事件而不重發通知。
逾時釋放與遲到付款要特別測試。若庫存已釋放並售給別人,遲到的成功 callback 不能自動製造負庫存,應進入人工查核與退款/替代處理。
超商取貨要保存 provider 回傳的門市代碼、名稱與地址快照。使用者選店後,後端再次驗證回傳格式與訂單 ownership,不接受任意前端填入的門市代碼。
門市可能停止服務,因此物流建單前仍要處理 provider 拒絕。畫面應讓顧客重新選店,而不是把付款標成失敗。
若商品不適合超商尺寸、重量或保存條件,後端應依訂單品項停用該方式;不要只在 UI 隱藏。
付款成功後建立 shipment ready,worker 再呼叫物流 API。成功保存 provider shipment ID;暫時失敗採有限次退避重試;永久失敗進入客服待辦。
物流狀態更新同樣驗證 provider 回傳並冪等處理。人工修改狀態需原因與操作者。不要把物流 provider 的所有原始狀態直接暴露給顧客,應轉成一致文案:處理中、已出貨、已到店、已取貨、異常。

圖 27-3:門市只能由 Sandbox 電子地圖結果選取;物流 timeout 進入 retry,不會回滾付款。
結帳只在業務需要時收發票資訊:個人電子發票、手機條碼載具、捐贈碼或公司統編/抬頭。欄位依最新服務商與財政部規格驗證,並明示用途。
付款成功後建立 invoice_request pending,由獨立 worker 開立。開立失敗不回滾付款或物流,而是進入財務待辦。折讓、作廢與退款要另有事件,不能直接刪除發票紀錄。
教學環境可以實作 adapter 與 mock response;沒有正式資格與 provider 設定時,不宣稱已完成合法正式開票。
請新增 invoice_requests 與發票 adapter 介面。
支援個人、載具、捐贈與公司統編所需的最小欄位,但先使用 mock provider。
付款成功後排入 pending;成功、失敗、作廢與折讓保存獨立事件。發票失敗不得改變 payment 或 shipment 狀態。
畫面清楚標示目前為測試流程,正式啟用前需要商家資格、服務設定與最新版規格驗證。
後台用交叉狀態找問題:
每個人工動作都要記錄原因。客服只能處理訂單與物流,財務才可處理退款與發票,管理者負責 provider 設定。

圖 27-4:已付款但物流失敗、已出貨退款、遲到付款與發票失敗各自進入對應人工流程。
至少測試:
請執行電商外部整合故障演練。
測試正常流程、付款 callback 重送、錯誤簽章、金額不符、物流 timeout、失效門市、發票失敗、逾時後遲到付款與已出貨退款。
逐項檢查 order、payment、inventory、shipment、invoice 的獨立狀態和事件,證明一個外部服務失敗不會污染其他狀態。
用綠界測試環境完成一筆超商取貨訂單。先讓正常流程通過,再故意讓物流 endpoint timeout、讓 invoice mock 回傳失敗,最後重送相同付款 callback。確認只有一次扣庫存,付款仍為成功,物流與發票各自出現在正確待辦。
你可以接著問 Lovable:「請依我的付款、物流與發票服務商,產生交叉狀態營運看板與故障演練。」下一章會改做中小企業採購簽核,處理角色、金額門檻與不可覆寫的決策紀錄。
嗨!我是 Wolke,曾任 Google Developer Expert(GDE,2019–2023) 與 LINE API Expert。我熱衷於研究 AI Agent、n8n 自動化工作流及全端開發架構,致力於將 AI 技術轉化為實際的生產力工具。
如果你喜歡這篇文章,歡迎透過以下方式與我交流,獲取更多技術實戰內容:
📚 技術著作:《實用的 Gemini API 開發點子書》,帶你運用 Gemini App、Google AI Studio、Gemini CLI 與 Antigravity IDE,打造 AI Agent 與實用產品。
📝 技術部落格:歡迎追蹤我的 Medium,我會持續分享 Agentic Automation、架構設計與實際開發的踩坑心得。
🎤 技術講座:我持續受邀至技術社群及研討會,分享 AI Agent、自動化工作流、DevOps 與全端開發實戰。曾於 2026 年 6 月 26 日的 DevOpsDays Taipei 2026 主講「不再只是寫腳本!讓 AI 代理人成為你的 SRE 最佳夥伴」工作坊。
如果你的企業、社群或學校正在尋找相關主題講者,歡迎私訊與我聯繫、洽談講座合作!
🎁 免費送 Lovable 額度給讀者!
我每個月會開放 10 個名額,每人 50 點 Lovable 額度,讓大家實際動手打造自己的網站或 App。
參加方式:
確認後,我會邀請你加入 Lovable workspace 並設定 50 點額度。名額有限,送完為止!